package com.biz.primus.ms.payment.channel.wechat;

import com.biz.primus.model.payment.enums.WechatTradeType;
import com.biz.primus.ms.payment.channel.wechat.lang.CertificateLoader;
import com.biz.primus.ms.payment.channel.wechat.lang.CheckName;
import com.biz.primus.ms.payment.channel.wechat.lang.Signer;
import com.biz.primus.ms.payment.channel.wechat.req.*;
import java.util.Properties;
import java.util.UUID;

import static com.biz.primus.ms.payment.channel.wechat.lang.Keys.*;

/**
 * 微信通讯方法工厂
 */
public class WeChatPayFactory {

    private static class WeChatPayFactoryHolder {
        static WeChatPayFactory instance = new WeChatPayFactory();
    }

    private WeChatPayFactory() {

    }

    public static WeChatPayFactory newInstance() {
        return WeChatPayFactoryHolder.instance;
    }

    public Signer newSigner(Properties configProperties, String key) {
        return new Signer(configProperties, key);
    }


    /**
     * @param configProperties {@link Properties}
     * @param outTradeNo 商户订单号
     * @param body 商品描述
     * @param totalFee 总金额, 金额单位为【分】
     * @param clientIp 终端IP
     * @param tradeType APP和网页支付提交用户端ip
     * @return {@link UnifiedOrder}
     */
    public UnifiedOrder newUnifiedOrder(Properties configProperties, String notifyUrl, String outTradeNo, String body,
                                        Integer totalFee, String clientIp, WechatTradeType tradeType, String timeExpire, String openid) {
        UnifiedOrder unifiedOrder = new UnifiedOrder(outTradeNo, body, totalFee, clientIp, tradeType, timeExpire, openid);
        setConfigurations(configProperties, unifiedOrder);
        unifiedOrder.setProperty(ATTACH, configProperties.getProperty(KEY));
        unifiedOrder.setProperty(NOTIFY_URL, notifyUrl);
        return unifiedOrder;
    }

    /**
     * 微信的订单号[transactionId]，优先使用.<br/>
     * 当没提供 微信的订单号[transactionId] 时需要传 商户系统内部的订单号[outTradeNo]。<br/>
     * 可以二选一,不能同时为空.
     *
     * @param transactionId 微信订单号
     * @param outTradeNo 商户订单号
     * @return {@link OrderQuery}
     */
    public OrderQuery newOrderQuery(Properties configProperties, String transactionId, String outTradeNo) {
        OrderQuery orderQuery = new OrderQuery(transactionId, outTradeNo);
        setConfigurations(configProperties, orderQuery);
        return orderQuery;
    }

    /**
     * @param outTradeNo 商户订单号
     * @return {@link OrderRefund}
     */
    public CloseOrder newCloseOrder(Properties configProperties, String outTradeNo) {
        CloseOrder closeOrder = new CloseOrder(outTradeNo);
        setConfigurations(configProperties, closeOrder);
        return closeOrder;
    }

    /**
     * 微信的订单号[transactionId]，优先使用.<br/>
     * 当没提供 微信的订单号[transactionId] 时需要传 商户系统内部的订单号[outTradeNo]。<br/>
     * 可以二选一,不能同时为空.
     *
     * @param transactionId 微信的订单号
     * @param outTradeNo 商户系统内部的订单号
     * @param outRefundNo 商户退款单号
     * @param totalFee 总金额
     * @param refundFee 退款金额
     * @return {@link OrderRefund}
     */
    public OrderRefund newOrderRefund(Properties configProperties, String transactionId, String outTradeNo,
                                      String outRefundNo, Integer totalFee, Integer refundFee) {
        OrderRefund refundOrder = new OrderRefund(transactionId, outTradeNo, outRefundNo, totalFee, refundFee);
        refundOrder.setSslContext(new CertificateLoader(configProperties.getProperty(LOAD_IDENTIFICATION), configProperties.getProperty(MCH_ID)).getSSLContext());
        setConfigurations(configProperties, refundOrder);
        refundOrder.setProperty(OP_USER_ID, configProperties.getProperty(MCH_ID));
        return refundOrder;
    }

    /**
     * refundId、outRefundNo 两个参数必填一个，如果同时存在优先级为 refundId > outRefundNo
     *
     * @param refundId 微信退款单号
     * @param outRefundNo 商户退款单号
     * @return {@link RefundQuery}
     */
    public RefundQuery newRefundQuery(Properties configProperties, String refundId, String outRefundNo) {
        RefundQuery refundQuery = new RefundQuery(refundId, outRefundNo);
        setConfigurations(configProperties, refundQuery);
        return refundQuery;
    }

    /**
     * 微信转账
     *
     * @param partnerTradeNo 商户的转账订单号。必填
     * @param openid 微信用户openid。必填
     * @param amount 付款金额，单位为分。必填
     * @param desc 付款操作说明信息。必填
     * @param checkName 校验用户姓名选项。必填
     * @param receiverName 收款用户姓名。如果check_name设置为FORCE_CHECK或OPTION_CHECK，则必填用户真实姓名。
     * @return {@link Transfer}
     */
    public Transfer newTransfer(Properties configProperties, String partnerTradeNo, String openid, Integer amount,
                                String desc, CheckName checkName, String receiverName) {
        Transfer transfer =
                new Transfer(partnerTradeNo, openid, amount, desc, checkName, receiverName);
        transfer.setSslContext(new CertificateLoader(configProperties.getProperty(LOAD_IDENTIFICATION), configProperties.getProperty(MCH_ID)).getSSLContext());
        setConfigurations(configProperties, transfer);
        transfer.setProperty(MCH_APPID, configProperties.getProperty(APPID));
        transfer.setProperty(MCHID, configProperties.getProperty(MCH_ID));
        transfer.setProperty(SPBILL_CREATE_IP, configProperties.getProperty(SPBILL_CREATE_IP));
        return transfer;
    }

    /**
     * 微信转账查询
     *
     * @param partnerTradeNo 商户转账单号
     * @return {@link TransferQuery}
     */
    public TransferQuery newTransferQuery(Properties configProperties, String partnerTradeNo) {
        TransferQuery refundQuery = new TransferQuery(partnerTradeNo);
        setConfigurations(configProperties, refundQuery);
        refundQuery.setSslContext(
                new CertificateLoader(configProperties.getProperty(LOAD_IDENTIFICATION),
                        configProperties.getProperty(MCH_ID)).getSSLContext());
        return refundQuery;
    }

    @SuppressWarnings("rawtypes")
    private void setConfigurations(Properties wechatPaymentReqVo, WechatPayRequestBase wechatPayRequestBase) {
        wechatPayRequestBase.setProperties(wechatPaymentReqVo);
        //        wechatPayRequestBase.setProperty(APPID, wechatPaymentReqVo.getAppId());
        //        wechatPayRequestBase.setProperty(MCH_ID, getPropertyByAppId(MCH_ID, appId));
        //        wechatPayRequestBase.setProperty(KEY, getPropertyByAppId(KEY, appId));
        //        String subAppid = getPropertyByAppId(SUB_APPID, appId);
        //        if (StringUtils.isNotBlank(subAppid))
        //            wechatPayRequestBase.setProperty(SUB_APPID, subAppid);
        //        String subMchid = getPropertyByAppId(SUB_MCH_ID, appId);
        //        if (StringUtils.isNotBlank(subMchid))
        //            wechatPayRequestBase.setProperty(SUB_MCH_ID, subMchid);
        wechatPayRequestBase.setProperty(NONCE_STR, UUID.randomUUID().toString());
    }

}
